package com.leyou.service.impl;

import com.leyou.entity.User;
import com.leyou.mapper.UserMapper;
import com.leyou.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.zip.DataFormatException;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    // 原因分析：因为Spring的默认的事务规则是遇到运行异常（RuntimeException）和程序错误（Error）才会回滚。

    /**
     * Spring事务失效的三种情况：
     * 1.在Spring事务配置成功的情况下，没有指明 rollback-for 属性，如果发生非 RuntimeException 异常，事务不会回滚。
     * 2.事务方法一定要用public修饰，否则也会造成事务不会回滚。原因：不使用public修饰会导致Spring的Cglib代理调用目标方法失效。
     * 3.在同一个类中两个方法直接调用，不会被Spring的事务拦截器拦截，因此不会回滚。只有目标方法由外部调用，才能被Spring的事务拦截器拦截。
     */

    /**
     * 参考博客：
     *      https://www.jianshu.com/p/380a9d980ca5
     *      https://blog.csdn.net/nextyu/article/details/78669997
     *      https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html
     *
     */

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUser() throws Exception {
        User user = new User();
        user.setId(16L);
        user.setUsername("helele");
        userMapper.updateByPrimaryKeySelective(user);
//        throw new RuntimeException("RuntimeException!");//RuntimeException 运行时异常——事务会回滚
        throw new DataFormatException("DataFormatException!");//非运行时异常——事务不会回滚
    }

    @Transactional(propagation = Propagation.SUPPORTS,readOnly = true)
    @Override
    public User getUserById() {
        return userMapper.selectByPrimaryKey(16L);
    }

    @Transactional
    @Override
    public User saveUser() throws Exception {
        User user = new User();
        user.setUsername("orange666");
        user.setPassword("xxxxxxxxxxxxx");
        user.setCreated(new Date(System.currentTimeMillis()));
        user.setPhone("13250840906");
        userMapper.insert(user);
        log.info(user.toString());
        return user;
    }

    @Transactional
    @Override
    public void testTransaction() throws Exception {
        saveUser();
        throw new DataFormatException("出错了!");
    }
}
